package com.example.upload.tool;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;

/**
 * @description: 简单的HTTP POST JSON请求工具
 * @author: song
 * @date: 2021-07-29 16:45
 **/
@Slf4j
public class EasyHttpTool {

    /**
     * 设置超时时间（单位:秒），会同时设置readTime和connectTime
     */
    private final static int TIME_OUT = 120;

    private final static Charset charset = Charset.forName("utf-8");

    public static volatile boolean isPrintLog=true;

    /**
     * JSON请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> List<T> postJsonByList(String url, Map<String, Object> params, Class<T> clazz) throws Exception {
        return postJsonByList(url, params, null, clazz);
    }

    public static <T> List<T> postJsonByList(String url, Map<String, Object> params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executePostJSON(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseArray(rs, clazz);
        } else {
            return null;
        }
    }


    public static <T> List<T> postJsonByList(String url, Object params, Class<T> clazz) throws Exception {
        return postJsonByList(url, params, null, clazz);
    }

    public static <T> List<T> postJsonByList(String url, Object params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executePostJSON(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseArray(rs, clazz);
        } else {
            return null;
        }
    }


    /**
     * JSON请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> T postJsonByObject(String url, Map<String, Object> params, Class<T> clazz) throws Exception {
        return postJsonByObject(url, params, null, clazz);
    }

    /**
     * JSON请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> T postJsonByObject(String url, Map<String, Object> params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executePostJSON(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseObject(rs, clazz);
        } else {
            return null;
        }
    }


    /**
     * JSON请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> T postJsonByObject(String url,Object params, Class<T> clazz) throws Exception {
        return postJsonByObject(url, params, null, clazz);
    }

    /**
     * JSON请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> T postJsonByObject(String url,Object params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executePostJSON(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseObject(rs, clazz);
        } else {
            return null;
        }
    }


    /**
     * get请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> T getByObject(String url, Map<String, Object> params, Class<T> clazz) throws Exception {
        return getByObject(url, params, null, clazz);
    }


    /**
     * get请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> List<T> getByList(String url, Map<String, Object> params,Class<T> clazz) throws Exception {
        return getByList(url, params, null, clazz);
    }


    /**
     * get请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> T getByObject(String url, Map<String, Object> params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executeGet(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseObject(rs, clazz);
        } else {
            return null;
        }
    }


    /**
     * get请求数据
     *
     * @param url    接口地址
     * @param params 参数
     * @param clazz  期望返回的结果类型
     * @return
     * @throws Exception
     */
    public static <T> List<T> getByList(String url, Map<String, Object> params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executeGet(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseArray(rs, clazz);
        } else {
            return null;
        }
    }

    /**
     * 执行POST JSON请求
     *
     * @param url
     * @param params
     * @return
     */
    private static HttpResponse executePostJSON(String url, Map<String, Object> params, Map<String, List<String>> headers) {
        String paramsStr = JSONObject.toJSONString(params);
        if(isPrintLog) {
            log.info("请求url:{},请求参数:{}", url, paramsStr);
        }
        HttpResponse response = HttpRequest.post(url)
                .header(headers)
                .body(paramsStr)
                .timeout(TIME_OUT * 1000)
                .charset(charset)
                .execute();
        return response;
    }


    public static <T> T postByObject(String url, Map<String, Object> params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executePost(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseObject(rs, clazz);
        } else {
            return null;
        }
    }



    public static <T> List<T> postByList(String url, Map<String, Object> params, Map<String, List<String>> headers, Class<T> clazz) throws Exception {
        HttpResponse response = executePost(url, params, headers);
        String rs = checkResponse(url, params, response);
        if (!StringUtils.isEmpty(rs)) {
            return JSONObject.parseArray(rs, clazz);
        } else {
            return null;
        }
    }

    /**
     * 执行POST formdata请求
     *
     * @param url
     * @param params
     * @return
     */
    private static HttpResponse executePost(String url, Map<String, Object> params, Map<String, List<String>> headers) {
        String paramsStr = JSONObject.toJSONString(params);
        if(isPrintLog) {
            log.info("请求url:{},请求参数:{}", url, paramsStr);
        }
        HttpResponse response = HttpRequest.post(url)
                .header(headers)
                .form(params)
                .timeout(TIME_OUT * 1000)
                .charset(charset)
                .execute();
        return response;
    }


    private static HttpResponse executePostJSON(String url, Object params, Map<String, List<String>> headers) {
        String paramsStr = JSONObject.toJSONString(params);
        if(isPrintLog) {
            log.info("请求url:{},请求参数:{}", url, paramsStr);
        }
        HttpResponse response = HttpRequest.post(url)
                .header(headers)
                .body(paramsStr)
                .timeout(TIME_OUT * 1000)
                .charset(charset)
                .execute();
        return response;
    }

    /**
     * 执行GET请求
     *
     * @param url
     * @param params
     * @return
     */
    private static HttpResponse executeGet(String url, Map<String, Object> params, Map<String, List<String>> headers) {
        String paramsStr = JSONObject.toJSONString(params);
        if(isPrintLog) {
            log.info("请求url:{},请求参数:{}", url, paramsStr);
        }
        HttpResponse response = HttpRequest.get(url)
                .header(headers)
                .form(params)
                .timeout(TIME_OUT * 1000)
                .charset(charset)
                .execute();
        return response;
    }


    /**
     * 检查响应数据
     *
     * @param url
     * @param params
     * @param response
     * @return
     */
    private static String checkResponse(String url, Object params, HttpResponse response) {
        String paramsStr = JSONObject.toJSONString(params);
        if (response.isOk()) {
            String rsStr = response.body();
            if(isPrintLog){
                log.info("请求url:{},请求参数:{},服务器响应数据:{}", url, paramsStr, rsStr);
            }
            if (StringUtils.isEmpty(rsStr)) {
                String error = "请求url:" + url + "时,服务器响应错误,请求数据:" + paramsStr + ",响应数据:" + response.toString();
                log.error(error);
                throw new RuntimeException(error);
            }
            JSONObject rs = JSONObject.parseObject(rsStr);
            if (rs.getInteger("code") == null || rs.getIntValue("code") != 0) {
                String error = "请求url:" + url + "时,服务器响应错误,请求数据:" + paramsStr + ",响应数据:" + rsStr;
                log.error(error);
                throw new RuntimeException(error);
            }
            String data = rs.getString("data");
            if (data == null || StringUtils.isEmpty(data.trim())) {
                return null;
            }
            return data;
        } else {
            String error = "请求url:" + url + "时,服务器响应错误,请求数据:" + paramsStr + ",响应数据:" + response.toString();
            log.error(error);
            throw new RuntimeException(error);
        }
    }

}
